package cn.spdb.harrier.server.master.deal;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.spdb.harrier.common.utils.Stopper;
import cn.spdb.harrier.server.entity.JobExecutionContext;
import cn.spdb.harrier.server.master.MasterManagerService;

public class PendingDeal implements Runnable,Deal {

	private Logger logger = LoggerFactory.getLogger("Master-"+this.getClass().getSimpleName());

/**
 * 任务等待队列，用于存放处于 PENDING 状态的任务上下文对象。
 *
 * <p>该队列是一个线程安全的优先级队列，基于自定义的比较器 {@link Comparator<JobExecutionContext>} 实现，
 * 确保每次从队列中取出的任务是“优先级最高”或“挂起时间最早”的任务。
 *
 * <h3>排序规则如下：</h3>
 * <ol>
 *   <li><b>优先级（Priority）不同</b>：优先级高的任务排在前面。</li>
 *   <li><b>优先级相同</b>：
 *     <ul>
 *       <li>若两个任务的挂起时间（PendingTime）相同，则按作业名（Job Name）进行字典序排序。</li>
 *       <li>若挂起时间不同，则较早挂起的任务排在前面。</li>
 *     </ul>
 *   </li>
 * </ol>
 */
private PriorityBlockingQueue<JobExecutionContext> pendingQueue = new PriorityBlockingQueue<JobExecutionContext>(
        200, // 初始容量为 200
        new Comparator<JobExecutionContext>() {
            @Override
            public int compare(JobExecutionContext o1, JobExecutionContext o2) {
                // 如果任意一个任务为空，视为相等，避免空指针异常
                if (o1 == null || o2 == null) {
                    return 0;
                }

                // 首先比较任务优先级
                if (o1.getPriority() == o2.getPriority()) {
                    // 优先级相同，再根据挂起时间排序
                    if (o1.getPendingTime() != null && o2.getPendingTime() != null) {
                        // 挂起时间也相同，则按作业名称字典序排序
                        if (o1.getPendingTime().equals(o2.getPendingTime())) {
                            return o1.getJob().compareTo(o2.getJob());
                        }
                        // 否则按挂起时间先后排序
                        return o1.getPendingTime().compareTo(o2.getPendingTime());
                    }
                }

                // 默认按优先级降序排列（高优先级在前）
                return o2.getPriority() - o1.getPriority();
            }
        });


	private final AtomicBoolean STOP = new AtomicBoolean(false);
	private MasterManagerService masterService;

/**
 * 任务等待处理线程的主执行方法。
 *
 * <p>该方法是一个无限循环，持续从优先级队列中取出处于 PENDING 状态的任务，
 * 并依次进行以下操作：
 * <ul>
 *   <li>检查任务是否在允许执行的时间窗口内</li>
 *   <li>检查任务的所有依赖是否满足</li>
 *   <li>如果任务是虚拟任务，则直接标记为成功</li>
 *   <li>否则将任务状态设置为 DISPATCHER（调度中）并加入调度队列</li>
 * </ul>
 */
@Override
public void run() {
    // 主循环，只要系统未停止就一直运行
    while (Stopper.isRunning()) {
        try {
            // 如果当前线程被暂停（STOP 为 true），则休眠 10 秒后继续等待
            if (STOP.get()) {
                Thread.sleep(1000 * 10);
                continue;
            }

            // 从优先级队列中取出下一个要处理的任务（按优先级、挂起时间等排序）
            JobExecutionContext jobContext = pendingQueue.take();

            // 检查任务是否在配置的时间窗口内执行
            if (!masterService.checkJobWinds(jobContext.getUdsJobConfig())) {
                logger.debug("job:{} is not pass Winds {}", jobContext,
                        jobContext.getUdsJobConfig().getTimeWindow());
                continue; // 时间窗口不匹配，跳过该任务
            }

            // 检查任务的所有前置依赖是否已完成
            if (!masterService.checkDependency(jobContext.getUdsJob())) {
                logger.debug("job is not dependency,jog:{}", jobContext);
                continue; // 存在未完成的依赖任务，跳过该任务
            }

            // 判断任务是否为“虚拟任务”
            if (jobContext.getUdsJobConfig().getVirtualEnable()) {
                // 虚拟任务不需要实际执行，直接标记为成功

                // 设置调度时间和开始时间为当前时间
                jobContext.getUdsJob().setDispatcherTime(LocalDateTime.now());
                jobContext.getUdsJob().setStartTime(LocalDateTime.now());

                // 增加任务触发次数
                jobContext.getUdsJob().setNumTimes(jobContext.getUdsJob().getNumTimes() + 1);

                // 清除服务器名称（因为没有实际调度到 Worker）
                jobContext.getUdsJob().setServerName("");

                // 打印虚拟任务完成日志
                logger.info("job is virtual conversion success,jog:{}", jobContext);

                // 标记任务为 SUCCESS 成功状态
                masterService.conversionSuccess(jobContext);

                // 处理后续依赖任务和信号流
                masterService.conversionSuccessAfter(jobContext);

                // 插入任务记录到数据库
                masterService.insertJobRecord(jobContext);
            } else {
                // 非虚拟任务：进入调度流程

                // 将任务状态更新为 DISPATCHER，并记录调度时间
                masterService.conversionDispatcher(jobContext);

                // 加入调度队列，等待进一步执行
                masterService.addDispatcherDealQueue(jobContext);
            }
        } catch (InterruptedException e) {
            // 捕获中断异常，打印堆栈信息
            e.printStackTrace();
        }
    }
}


	public void addQueue(JobExecutionContext jobContext) {
		pendingQueue.offer(jobContext);
	}

	public void start() {
		STOP.set(false);
	}

	public void stop() {
		STOP.set(true);
		pendingQueue.clear();
	}

	public PendingDeal(MasterManagerService masterService) {
		this.masterService = masterService;
	}
}
